﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
using System.Net;
using System.Collections;

namespace TrifleCommon
{
    public class Logger
    {
        protected static ILog _infologger;
        protected static ILog _exceptionLogger;

        /// <summary>
        /// 日志记录器
        /// </summary>
        protected static ILog InfoLogger
        {
            get
            {
                return _infologger;
            }
        }

        /// <summary>
        /// 异常日志记录器
        /// </summary>
        protected static ILog ExceptionLogger
        {
            get
            {
                return _exceptionLogger;
            }
        }

        static Logger()
        {
            try
            {
                log4net.Config.XmlConfigurator.Configure();
                _infologger = log4net.LogManager.GetLogger("InfoLogger");
                _exceptionLogger = log4net.LogManager.GetLogger("ExceptionLogger");
            }
            catch
            {

            }
        }

        public static void Info(string msg)
        {
            try
            {
                InfoLogger.Info(msg);
            }
            catch
            {

            }
        }

        public static void Info(string msg, string frame)
        {
            try
            {
                InfoLogger.Info(frame + " " + msg + " " + frame);
            }
            catch
            {

            }
        }

        public static void Exception(string title, Exception ex)
        {
            try
            {
                InfoLogger.Info("[Exception] " + title);
                ExceptionLogger.Info(title + FormatExceptionData(ex));
            }
            catch
            {

            }
        }

        public static void Exception(string title, string message)
        {
            try
            {
                //不能调用Exception方法偷懒，为了准确得去除手动生成的没有堆栈的异常中的Logger类内堆栈调用信息
                InfoLogger.Info("[Exception] " + title);
                ExceptionLogger.Info(title + FormatExceptionData(new Exception(message)));
            }
            catch
            {

            }
        }

        /// <summary>
        /// 无堆栈异常记录
        /// </summary>
        public static void Error(string title, string message)
        {
            try
            {
                InfoLogger.Info("[Exception] " + title);
                ExceptionLogger.Info(title);
            }
            catch
            {

            }
        }



        #region ------ 辅助方法 ------

        /// <summary>
        /// 异常来源
        /// </summary>
        protected static void FormatExceptionSource(ref StringBuilder sb)
        {
            sb.Append(' ', 2).Append("ServerName:\t").
                Append(Dns.GetHostName()).
                Append(Environment.NewLine);
            sb.Append(' ', 2).Append("ServerIP:\t").
                Append(Dns.GetHostAddresses(Dns.GetHostName())[0].ToString());
        }

        /// <summary>
        /// 异常附带的参数信息
        /// </summary>
        protected static bool FormatExceptionParameter(ref StringBuilder sb, ref Exception ex)
        {
            if (ex != null && ex.Data != null && ex.Data.Count != 0)
            {
                sb.Append(' ', 2).Append("Data:");
                sb.Append(Environment.NewLine);
                sb.Append(' ', 4);
                sb.Append("key");
                sb.Append("\t\t");
                sb.Append("value");
                IEnumerator ir = ex.Data.Keys.GetEnumerator();
                while (ir.MoveNext())
                {
                    string key = (string)ir.Current;
                    sb.Append(Environment.NewLine);
                    sb.Append(' ', 4);
                    sb.Append(key);
                    sb.Append("\t\t");
                    sb.Append(ex.Data[key].ToString());
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// 异常描述
        /// </summary>
        protected static void FormatExceptionMessage(ref StringBuilder sb, ref Exception ex)
        {
            sb.Append(ex.GetType().ToString());
            if (ex.Message != "")
                sb.Append(": ");
            sb.Append(ex.Message);
        }

        /// <summary>
        /// 异常堆栈
        /// </summary>
        protected static void FormatExceptionStackTrace(ref StringBuilder sb, ref Exception ex)
        {
            if (ex.StackTrace == null)
            {
                //如果是手动生成的Exception没有堆栈信息，于是通过环境堆栈计算之。
                //(由于Logger内的堆栈不一，所以现在只去除了可去除的最小堆栈信息)
                string trace = Environment.StackTrace;
                int newlineIndex = 0;
                for (int i = 0; i != 5; ++i)
                {
                    newlineIndex = trace.IndexOf("\r\n", newlineIndex) + 2;
                }
                sb.Append(trace.Substring(newlineIndex));
            }
            else
            {
                sb.Append(ex.StackTrace);
            }

            Exception baseEx = ex.GetBaseException();
            if (baseEx != null)
            {
                sb.Append(Environment.NewLine).Append(Environment.NewLine);
                sb.AppendLine("-----base exception----");
                sb.Append(baseEx.GetType().ToString());
                if (baseEx.Message != "")
                    sb.Append(": ");
                sb.Append(baseEx.Message);
                sb.Append(baseEx.StackTrace);
            }

            Exception innerEx = ex.InnerException;
            if (innerEx != null)
            {
                sb.Append(Environment.NewLine).Append(Environment.NewLine);
                sb.AppendLine("-----Inner exception----");
                sb.Append(innerEx.GetType().ToString());
                if (innerEx.Message != "")
                    sb.Append(": ");
                sb.Append(innerEx.Message);
                sb.Append(innerEx.StackTrace);
            }
        }

        public static string FormatExceptionData(Exception ex)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(Environment.NewLine);
            FormatExceptionSource(ref sb); sb.Append(Environment.NewLine);
            if (FormatExceptionParameter(ref sb, ref ex))
                sb.Append(Environment.NewLine);
            FormatExceptionMessage(ref sb, ref ex); sb.Append(Environment.NewLine);
            FormatExceptionStackTrace(ref sb, ref ex); sb.Append(Environment.NewLine);
            return sb.ToString();
        }

        #endregion ------ 辅助方法 ------
    }
}
